#pragma once
#include "logger.hpp"
#include "common.hpp"
#include "inet_addr.hpp"
namespace socket_module
{
    using namespace logger_module;
    const int default_backlog=10;
    class Socket
    {
    public:
        virtual void SocketOrDie() = 0;
        virtual void BindOrDie(uint16_t) = 0;
        virtual void ListenOrDie(int backlog) = 0;
        virtual std::shared_ptr<Socket> Accept(InetAddr& client)=0;
        virtual void Close()=0;
        virtual bool Connect(InetAddr&server,uint16_t port)=0;
        virtual int Recv(std::string *out)=0;
        virtual int Send(std::string& message)=0;
        virtual int Fd()=0;
    public:
        void BulidTcpSocket()
        {
            SocketOrDie();
        }
        void BulidTcpSocket(uint16_t port, int backlog = default_backlog)
        {
            SocketOrDie();
            BindOrDie(port);
            ListenOrDie(default_backlog);
        }
    };
    
    const static int defaultfd=-1;
    class TcpSocket:public Socket
    {
    public:
        TcpSocket():_sockfd(defaultfd)
        {}
        TcpSocket(int fd):_sockfd(fd)
        {}
        ~TcpSocket(){}
        void SocketOrDie() override
        {
            _sockfd=socket(AF_INET,SOCK_STREAM,0);
            if(_sockfd<0)
            {
                LOG(log_level::FATAL)<<"socket error";
                exit(SOCKET_ERR);
            }
            LOG(log_level::INFO)<<"sockfd is"<<_sockfd;
        }
        void BindOrDie(uint16_t port) override
        {
            InetAddr localAddr(port);
            int n=bind(_sockfd,localAddr.NetAddrPtr(),localAddr.Addrlen());
            if(n!=0)
            {
                LOG(log_level::FATAL)<<"bind fail";
                exit(BIND_ERR);
            }
            LOG(log_level::INFO)<<"bind success";
        }
        void ListenOrDie(int backlog=default_backlog) override
        {
            int n = listen(_sockfd,backlog);
            if(n!=0)
            {
                LOG(log_level::FATAL)<<"listen fail";
                exit(LISTEN_ERR);
            }
            LOG(log_level::INFO)<<"listen success";
        }
        
        std::shared_ptr<Socket> Accept(InetAddr& client) override
        {
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            int client_fd=accept(_sockfd,TO_SOCKADDR(peer),&len);
            if(client_fd<0)
            {
                LOG(log_level::ERROR)<<"accept wrong";
                return nullptr;
            }
            client.SetAddr(peer);
            return std::make_shared<TcpSocket>(client_fd);
        }
        void Close() override
        {
            int n=close(_sockfd);
            if(n!=0)
            {
                LOG(log_level::FATAL)<<"close fail";
                exit(CLOSE_ERR);
            }
            LOG(log_level::INFO)<<"close success";
        }
        bool Connect(InetAddr&server,uint16_t port) override
        {
            int n=connect(_sockfd,server.NetAddrPtr(),server.Addrlen());
            if(n!=0)
            {
                LOG(log_level::FATAL)<<"connect fail";
                exit(CONNECT_ERR);
            }
            LOG(log_level::INFO)<<"connect success";
            return true;
        }
        int Recv(std::string *out) override
        {
            char buffer[1024];
            int n=recv(_sockfd,buffer,sizeof(buffer)-1,0);
            if(n>0)
            {
                buffer[n]=0;
                *out +=buffer;
            }
            return n;
        }
        int Send(std::string& message) override
        {
            return send(_sockfd,message.c_str(),sizeof(message),0);
        }
        int Fd()override
        {
            return _sockfd;
        }
    private:
        int _sockfd;
    };
}